/**
 * 回调函数类型别名，可以接受任意数量和类型的参数。
 */
type Callback = (...args: any) => void;

/**
 * EventEmitter 类，用于订阅、触发和移除事件监听器。
 */
class EventEmitter {
    /**
     * 存储每个事件的监听器。
     * @private
     */
    private listeners: Record<string, Set<Callback>> = {};

    /**
     * 存储每个事件最后一次触发的参数。
     * @private
     */
    private lastEmitted: Record<string, any> = {};

    /**
     * 为指定的事件添加监听器。
     * 如果该事件已经被触发过，则立即调用监听器并传入最后一次触发的参数。
     * 
     * @param eventName - 要监听的事件名称。
     * @param listener - 事件触发时调用的回调函数。
     */
    on(eventName: string, listener: Callback) {
        /**
         * 如果该事件还没有监听器，则创建一个新的监听器集合。
         */
        if (!this.listeners[eventName]) {
            this.listeners[eventName] = new Set();
        }
        /**
         * 将监听器添加到该事件的监听器集合中。
         */
        this.listeners[eventName].add(listener);

        /**
         * 如果该事件已经被触发过，立即调用监听器并传入最后一次触发的参数。
         */
        if (this.lastEmitted[eventName]) {
            listener(...this.lastEmitted[eventName]!);
        }
    }

    /**
     * 移除指定事件的监听器。
     * 
     * @param eventName - 要移除监听的事件名称。
     * @param listener - 要移除的事件监听器回调函数。
     */
    off(eventName: string, listener: Callback) {
        /**
         * 如果该事件有监听器，则从集合中删除指定的监听器。
         */
        this.listeners[eventName]?.delete(listener);
    }

    /**
     * 触发指定的事件，并传入参数。
     * 调用所有注册的监听器，并将参数传递给它们。
     * 
     * @param eventName - 要触发的事件名称。
     * @param args - 要传递给监听器的参数。
     */
    emit(eventName: string, ...args: any) {
        /**
         * 存储该事件最后一次触发的参数。
         */
        this.lastEmitted[eventName] = args;
        /**
         * 如果该事件有监听器，则调用所有监听器并传入参数。
         */
        this.listeners[eventName]?.forEach(listener => listener(...args));
    }

    /**
     * 清除所有事件的监听器和最后一次触发的参数。
     */
    clear() {
        /**
         * 重置监听器和最后一次触发的参数。
         */
        this.listeners = {};
        this.lastEmitted = {};
    }
}

/**
 * 导出一个 EventEmitter 类的单例实例。
 */
export const EventEmitters = new EventEmitter();